import sys
from io import BytesIO
from Ui_facemain import Ui_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QImage
#from PyQt5.QtWidgets import QApplication, QMainWindow,QPushButton, QPlainTextEdit,QLabel,QMessageBox
import numpy as np
import cv2,os
import threading as th  # 导入threading包
import numpy as np
from PIL import Image



readflag=0
class myclass():
    def __init__(self) -> None:
        pass
class MainWindow(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super(MainWindow,self).__init__()
        self.setupUi(self)
        #在此输入connect链接
        #self.display.setStyleSheet('border-width: 1px;border-style: solid;border-color: rgb(20, 20, 20);background-color: rgb(100, 120, 140);')
        self.show()
        self.readbutton.clicked.connect(self.read)
        self.stopbutton.clicked.connect(self.stop)
        self.quitbutton.clicked.connect(self.quit)
        self.collectbutton.clicked.connect(self.collect)
        self.trainbutton.clicked.connect(self.train)
        self.recgbutton.clicked.connect(self.recognize)



        #self.timer_camera = QtCore.QTimer()  # 初始化定时器
        #self.timer_camera.timeout.connect(self.show_camera)
        self.result = []
        self.stop=0
        self.stopflag=0
        self.count = 0
        self.cam=0
        ok = QInputDialog.getInt(self, "摄像头选择", "输入摄像头代号0/1:", 0, 0, 1, 2)
        i=int(ok[0])
        print (i)
        self.cap = cv2.VideoCapture(i)


    def read(self):
        self.stopflag=1
        self.stopflag=0
        self.show_camera()

    def showimg(self,show):

        show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
        showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
        self.display.setPixmap(QtGui.QPixmap.fromImage(showImage))

    def show_camera(self):
       # 人脸识别
        faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

        # 识别眼睛
        eyeCascade = cv2.CascadeClassifier('haarcascade_eye.xml')

        # 开启摄像头
        ok = True

        result = []

        while ok:
            # 读取摄像头中的图像，ok为是否读取成功的判断参数
            ok, img = self.cap.read()
            # 转换成灰度图像
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

            # 人脸检测
            faces = faceCascade.detectMultiScale(
                gray,     
                scaleFactor=1.2,
                minNeighbors=5,     
                minSize=(32, 32)
                )

            # 在检测人脸的基础上检测眼睛
            for (x, y, w, h) in faces:
                fac_gray = gray[y: (y+h), x: (x+w)]
                result = []
                eyes = eyeCascade.detectMultiScale(fac_gray, 1.3, 2)

                # 眼睛坐标的换算，将相对位置换成绝对位置
                for (ex, ey, ew, eh) in eyes:
                    result.append((x+ex, y+ey, ew, eh))

            # 画矩形
            for (x, y, w, h) in faces:
                cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

            for (ex, ey, ew, eh) in result:
                cv2.rectangle(img, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)
            self.showimg(img) 

            k = cv2.waitKey(1)
            if k == 27:    #按 'ESC' to quit
                break
            if self.stopflag == 1:   # 通过esc键退出摄像
                break

    def stop(self):
        self.stopflag=1

    def quit(self):
        try:
            if self.timer_camera.isActive():
                self.timer_camera.stop()        
            if self.cap.isOpened():
                self.cap.release()
        except :
            None
            exit()

    def collect(self):
        countmax=0
        start=1
        path=os.getcwd()
        print(path) # 获取当前目录，os模块函数
        path2=path+'\Facedata'
        print(os.path.exists(path2))
        if not os.path.exists(path2):
            os.mkdir(path+'\\Facedata')       
        self.face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
        ok = QInputDialog.getInt(self, "输入ID", "输入当前用户ID:", 0, 0, 100, 2)
        print(ok[1]==True)
        if(ok[1]!=True):
            start=0
        self.face_id=int(ok[0])
        print(self.face_id)
        self.count=0
        max = QInputDialog.getInt(self, "输入采集量", "采集图片张数:", 600, 0, 2000, 2)
        print(max[1])
        if(max[1]!=True):
            start=0        
        countmax=int(max[0])

        print(start)
        if (start==1):
            self.stopflag=0
            self.collectface(countmax)
    def train(self):
        reply = QMessageBox.information(self,
                "提示", 
                "开始训练模型数据", 
                QMessageBox.Yes)          
        path = 'Facedata'
        recognizer = cv2.face.LBPHFaceRecognizer_create()
        detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
        def getImagesAndLabels(path):
            imagePaths = [os.path.join(path, f) for f in os.listdir(path)]  
            faceSamples = []
            ids = []
            for imagePath in imagePaths:
                PIL_img = Image.open(imagePath).convert('L')   # convert it to grayscale
                img_numpy = np.array(PIL_img, 'uint8')
                id = int(os.path.split(imagePath)[-1].split(".")[1])
                faces = detector.detectMultiScale(img_numpy)
                for (x, y, w, h) in faces:
                    faceSamples.append(img_numpy[y:y + h, x: x + w])
                    ids.append(id)
            return faceSamples, ids
        print('训练需要一定时间，请耐心等待....')
        faces, ids = getImagesAndLabels(path)
        recognizer.train(faces, np.array(ids))
        recognizer.write(r'./trainer.yml')
        reply = QMessageBox.information(self,
                "提示", 
                "训练完成", 
                QMessageBox.Yes)          

    def collectface(self,max):
        font = cv2.FONT_HERSHEY_SIMPLEX
        while True:
            sucess, img = self.cap.read()

            # 转为灰度图片

            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

     # 检测人脸

            faces = self.face_detector.detectMultiScale(gray, 1.3, 5)

            for (x, y, w, h) in faces:
                cv2.rectangle(img, (x, y), (x+w, y+w), (255, 0, 0))
                self.count += 1
                cv2.putText(img, str(self.count), (50,50), font, 1, (0, 0, 255), 3)
            # 保存图像
                cv2.imwrite("./Facedata/User." + str(self.face_id) + '.' + str(self.count) + '.jpg', gray[y: y + h, x: x + w])

            self.showimg(img)

            k = cv2.waitKey(1)

            if self.stopflag == 1:   # 通过esc键退出摄像
                reply = QMessageBox.information(self,
                "提示", 
                "采集中断", 
                QMessageBox.Yes)  
                break

            elif self.count >= max:  # 得到1000个样本后退出摄像
                reply = QMessageBox.information(self,
                  "提示", 
                  "人脸采集完成", 
                  QMessageBox.Yes)
                break
    def recognize(self):
        if (os.path.exists('trainer.yml'))==True:
            self.stopflag=0
            self.recgface()
        else:
            reply = QMessageBox.information(self,
                "错误", 
                "未找到训练模型数据，请先训练模型", 
                QMessageBox.Yes)  

    def recgface(self):
        recognizer = cv2.face.LBPHFaceRecognizer_create()
        recognizer.read('./trainer.yml')
        cascadePath = "haarcascade_frontalface_default.xml"
        faceCascade = cv2.CascadeClassifier(cascadePath)
        font = cv2.FONT_HERSHEY_SIMPLEX
        idnum = 0
        names = ['Hanyl', 'Qiyao']
        cam = self.cap
        minW = 0.1*cam.get(3)
        minH = 0.1*cam.get(4)
        while True:
            ret, img = cam.read()
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

            faces = faceCascade.detectMultiScale(
                gray,
                scaleFactor=1.2,
                minNeighbors=5,
                minSize=(int(minW), int(minH))
            )

            for (x, y, w, h) in faces:
                cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
                idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])

                if confidence < 100:
                    idnum = idnum
                    confidence = "{0}%".format(round(100 - confidence))
                else:
                    idnum = "unknown"
                    confidence = "{0}%".format(round(100 - confidence))

                cv2.putText(img, str(idnum), (x+5, y-5), font, 1, (0, 0, 255), 1)
                cv2.putText(img, str(confidence), (x+5, y+h-5), font, 1, (0, 255, 0), 1)
            self.showimg(img)
            k = cv2.waitKey(10)
            if k == 27:
                break
            if self.stopflag == 1:   # 通过esc键退出摄像
                break

                
if __name__ == "__main__":  # 主函数执行
    app = QApplication(sys.argv)
    globFont = QtGui.QFont()
    globFont.setFamily('Microsoft YaHei')
    globFont.setPointSize(10)
    app.setFont(globFont)
    MainUI = MainWindow()  # 将主界面定义为欢迎界面，程序运行至此处开始调用MainWindow()类
    sys.exit(app.exec_())  # 程序执行完毕后关闭
